package com.acousticpayment.acoustic_comm;

import java.util.ArrayList;
import java.util.BitSet;

public class Codec
{
	public static final int PREAMBLES = 0;
	public static final int RS232_DATA = 1;
	public static final int RS232_DATA_START = 2;
	public static final int RS232_DATA_STOP = 3;
	public static final int DATA_RECEIVED = 4;
	public static final int VALIDATE_DATA = 5;
	
	public static BitSet bitsGenerator(byte[] data)
	{
		// 10 bits data: 1 start bit, 1 stop bit, 1 parity bit, 8 data bits, 10 bits preambles
		
		int bitsLength = data.length*11+10;
		BitSet bits = new BitSet(bitsLength); // initialized as false
		int i;
		boolean parity;
		for(i = 0; i < 10; ++i)
		{
			bits.set(i);
		}
		for (int j = 0; j < data.length; ++j )
		{
			bits.set(i++, false); // start bit
			parity = false;
			// data bits
			for (int k = 0; k < 8; ++k)
			{
				if (((data[j]>>k)&0x01) == 0x01)
				{
					bits.set(i);
				}
				parity ^= bits.get(i);
				++i;
			}
			bits.set(i++, parity); // parity bit
			bits.set(i++);// stop bit
		}
		return bits;
	}	
	
	public static ArrayList<Byte> RS23210bitsDecode(BitSet bits)
	{
		int preamblesCount = 0;
		byte b = 0;
		int bitCount = 0;
		boolean isReceived = false;
		int state = PREAMBLES;
		int bytesReceived = 0;
		boolean parity = false;
		ArrayList<Byte> decodedData = new ArrayList<Byte>();
		int i;
		for (i = 0; i < bits.length() && (!isReceived); ++i)
		{	
			switch (state)
			{
				case PREAMBLES:
				{
					if (bits.get(i))
					{
						preamblesCount++;
					}
					else
					{
						preamblesCount = 0;
					}
					if (preamblesCount == 10)
					{
						state = RS232_DATA;
					}
				}break;
				case RS232_DATA:
				{
					if (bits.get(i) == false)
					{
						state = RS232_DATA_START;
						preamblesCount = 0;
						parity = false;
						b = 0x00;
					}
					else
					{
						preamblesCount++;
						if (preamblesCount<10)
						{
							state = RS232_DATA;
						}
						else
						{
							state = DATA_RECEIVED;
						}
					}
				}break;
				case RS232_DATA_START:
				{
					if (bits.get(i))
					{
						b |= (0x01<<bitCount);
					}
					parity ^= bits.get(i);
					bitCount++;
					if (bitCount == 8)
					{
						bitCount = 0;
						state = VALIDATE_DATA;
					}
				}break;
				case VALIDATE_DATA:
				{
					if (bits.get(i) == parity)
					{
						state = RS232_DATA_STOP;
						bytesReceived++;
						decodedData.add(b);
					}
					else
					{
						state = PREAMBLES;
					}
				}break;
				case RS232_DATA_STOP:
				{
					if (bits.get(i))
					{
						state = RS232_DATA;
					}
					else
					{
						state = PREAMBLES;
						decodedData.clear();
					}
				}break;
				case DATA_RECEIVED:
				{
					isReceived = true;
				}break;
			}
		}
		if (i == bits.length())
		{
			isReceived = true;
		}
		if (!isReceived)
		{
			decodedData.clear();
			decodedData = null;
		}
		return decodedData;
	}
}
